﻿using System.Collections.Specialized;
using System.Linq;
using System.Collections.Generic;
using EPiServer.Core;
using System;
using EPiServer.Filters;
using EPiServer.Security;
using EPiServer.SpecializedProperties;
using EPiServer.DataAbstraction;

namespace EPiSugar.UnitTesting
{
    public class FakePageProvider : PageProviderBase, IPageSource
    {
        public static int LastIdentity = 3;

        public PageData CurrentPage { get; set; }
        public IDictionary<PageReference, PageReferenceCollection> Lists { get; set; }
        public IDictionary<PageReference, PageData> Pages { get; set; }
        public PageTypeCollection PageTypes { get; set; }

        public FakePageProvider()
        {
            Lists = new Dictionary<PageReference, PageReferenceCollection>();
            Pages = new Dictionary<PageReference, PageData>();
        }

        public void Add(PageReference parentLink, params PageData[] pages)
        {
            IEnumerable<PageReference> links = from p in pages select p.PageLink;

            if (Lists.ContainsKey(parentLink))
                Lists[parentLink] = new PageReferenceCollection(Lists[parentLink].Union(links));
            else
                Lists[parentLink] = new PageReferenceCollection(links);

            foreach (var page in pages)
            {
                Pages[page.PageLink] = page;
            }
        }

        public PageDataCollection GetChildren(PageReference pageLink)
        {
            if(Lists.ContainsKey(pageLink))
                return new PageDataCollection(from pl in Lists[pageLink] select Pages[pl]);
            return new PageDataCollection();
        }

        public PageData GetPage(PageReference pageLink)
        {
            return Pages[pageLink];
        }

        protected override PageReferenceCollection GetChildrenReferences(PageReference pageLink, string languageID)
        {
            if(Lists.ContainsKey(pageLink))
                return Lists[pageLink];
            return new PageReferenceCollection();
        }

        protected override PageData GetLocalPage(PageReference pageLink, ILanguageSelector languageSelector)
        {
            return Pages[pageLink];
        }

        protected override Uri ResolveLocalPage(PageReference pageLink, out Guid guid)
        {
            PageData page = Pages[pageLink];
            guid = page.PageGuid;
            return new Uri(page.LinkURL);
        }

        protected override Uri ResolveLocalPage(Guid pageGuid, out PageReference pageLink)
        {
            PageData page = (from p in Pages.Values where p.PageGuid == pageGuid select p).First();
            pageLink = page.PageLink;
            return new Uri(page.LinkURL);
        }

        public override string Name
        {
            get { return ""; }
        }

        public override PageProviderCapabilities Capabilities
        {
            get { return PageProviderCapabilities.Copy | PageProviderCapabilities.Create | PageProviderCapabilities.Delete | PageProviderCapabilities.Edit | PageProviderCapabilities.Move | PageProviderCapabilities.Security; }
        }

        public override PageReference Copy(PageReference pageLink, PageReference destinationLink, bool publishOnDestination, bool allowThreading)
        {
            PageData page = GetPage(pageLink).CreateWritableClone();

            page.PageLink = new PageReference(++LastIdentity);
            page.ParentLink = destinationLink;
            Pages[page.PageLink] = page;
            AddToList(page.PageLink, destinationLink);

            return page.PageLink;
        }
        public override PageData CreateLanguageBranch(PageReference pageLink, ILanguageSelector selector)
        {
            return base.CreateLanguageBranch(pageLink, selector);
        }
        public override void Delete(PageReference pageLink, bool forceDelete)
        {
            PageData page = Pages[pageLink];
            Pages.Remove(pageLink);
            Lists[page.ParentLink].Remove(pageLink);
        }
        public override void DeleteChildren(PageReference pageLink, bool forceDelete)
        {
            base.DeleteChildren(pageLink, forceDelete);
        }
        public override void DeleteLanguageBranch(PageReference pageLink, string languageBranch)
        {
            base.DeleteLanguageBranch(pageLink, languageBranch);
        }
        public override void DeleteVersion(PageReference pageLink)
        {
            base.DeleteVersion(pageLink);
        }
        public override string Description
        {
            get
            {
                return base.Description;
            }
        }
        public override PageDataCollection FindPagesWithCriteria(PageReference pageLink, EPiServer.PropertyCriteriaCollection criterias, string languageBranch, ILanguageSelector selector)
        {
            return base.FindPagesWithCriteria(pageLink, criterias, languageBranch, selector);
        }

        public override PageData GetDefaultPageData(PageReference parentPageLink, int pageTypeID, ILanguageSelector selector)
        {
            try
            {
                return CreatePageData.DefaultPageData(pageTypeID, parentPageLink, selector);
            }
            catch (Exception)
            {
                // lets just fake it
                var page = new PageData();
                page.Property.Add("PageLink", new PropertyPageReference(PageReference.EmptyReference));
                page.Property.Add("PageParentLink", new PropertyPageReference(parentPageLink));
                page.Property.Add("PageName", new PropertyString(""));
                page.Property.Add("PageTypeID", new PropertyPageType(pageTypeID));
                page.Property.Add("PageTypeName", new PropertyString("PageType" + pageTypeID));
                page.Property.Add("PageVisibleInMenu", new PropertyBoolean(true));
                page.Property.Add("PageGUID", new PropertyString(Guid.NewGuid().ToString()));
                page.Property.Add("PageWorkStatus", new PropertyNumber((int)VersionStatus.Published));
                page.Property.Add("PageURLSegment", new PropertyString(""));
                page.Property.Add("PageChildOrderRule", new PropertySortOrder { Value = FilterSortOrder.Index });
                page.Property.Add("MainIntro", new PropertyString());
                page.Property.Add("MainBody", new PropertyXhtmlString());
                page.ACL.Add(new AccessControlEntry("Everyone", AccessLevel.FullAccess));
                return page;
            }
        }
        public override IList<PageReference> GetDescendents(PageReference pageLink)
        {
            return base.GetDescendents(pageLink);
        }
        public override PageDataCollection GetLanguageBranches(PageReference pageLink)
        {
            //return base.GetLanguageBranches(pageLink);
            return new PageDataCollection();
        }
        protected override PageDataCollection GetPages(PageReferenceCollection pageReferences, ILanguageSelector selector)
        {
            return base.GetPages(pageReferences, selector);
        }
        public override string GetUniqueUrlSegment(PageData changedPage, PageReference destinationLink)
        {
            return base.GetUniqueUrlSegment(changedPage, destinationLink);
        }

        public void Initialize(string name, NameValueCollection config, PageTypeCollection pageTypes)
        {
            config["entryPoint"] = config["entryPoint"] ?? PageReference.RootPage.ID.ToString();
            Initialize(name, config);
            PageTypes = pageTypes;
        }
        public override PageDataCollection ListDelayedPublish()
        {
            return base.ListDelayedPublish();
        }
        public override EPiServer.DataAbstraction.PageVersionCollection ListPublishedVersions(PageReference pageLink)
        {
            return base.ListPublishedVersions(pageLink);
        }
        public override EPiServer.DataAbstraction.PageVersionCollection ListVersions(PageReference pageLink)
        {
            return base.ListVersions(pageLink);
        }
        public override EPiServer.DataAbstraction.PageVersionCollection ListVersions(PageReference pageLink, string languageBranch)
        {
            return base.ListVersions(pageLink, languageBranch);
        }
        public override EPiServer.DataAbstraction.PageVersion LoadPublishedVersion(PageReference pageLink)
        {
            return base.LoadPublishedVersion(pageLink);
        }
        public override EPiServer.DataAbstraction.PageVersion LoadPublishedVersion(PageReference pageLink, string languageBranch)
        {
            return base.LoadPublishedVersion(pageLink, languageBranch);
        }
        public override EPiServer.DataAbstraction.PageVersion LoadVersion(PageReference pageLink)
        {
            return base.LoadVersion(pageLink);
        }
        public override void Move(PageReference pageLink, PageReference destinationLink)
        {
            PageData page = Pages[pageLink];

            Lists[page.ParentLink].Remove(pageLink);

            AddToList(pageLink, destinationLink);
            page.ParentLink = destinationLink;
        }

        private void AddToList(PageReference pageLink, PageReference destinationLink)
        {
            if (Lists.ContainsKey(destinationLink))
                Lists[destinationLink].Add(pageLink);
            else
                Lists[destinationLink] = new PageReferenceCollection(new[] { destinationLink });
        }

        public override void MoveToWastebasket(PageReference pageLink)
        {
            base.MoveToWastebasket(pageLink);
        }
        public override System.Web.Hosting.VirtualPathProvider PageFolderVirtualPathProvider
        {
            get
            {
                return base.PageFolderVirtualPathProvider;
            }
            set
            {
                base.PageFolderVirtualPathProvider = value;
            }
        }
        public override PageReference Save(PageData page, EPiServer.DataAccess.SaveAction action)
        {
            if (PageReference.IsNullOrEmpty(page.PageLink))
                page.PageLink = new PageReference(++LastIdentity);
            Add(page.ParentLink, page);
            return page.PageLink;
        }
        protected override void SetCacheSettings(PageData page, CacheSettings cacheSettings)
        {
            base.SetCacheSettings(page, cacheSettings);
        }
        protected override void SetCacheSettings(PageReference pageLink, PageReferenceCollection childrenReferences, CacheSettings cacheSettings)
        {
            base.SetCacheSettings(pageLink, childrenReferences, cacheSettings);
        }
        public override List<System.Web.Hosting.VirtualPathProvider> SupportedVirtualPathProvider
        {
            get
            {
                return base.SupportedVirtualPathProvider;
            }
            set
            {
                base.SupportedVirtualPathProvider = value;
            }
        }
        public override PageReference WastebasketReference
        {
            get
            {
                return base.WastebasketReference;
            }
        }
    }
}